package com.yingxue.lesson.service.impl;

import com.yingxue.lesson.constant.Constant;
import com.yingxue.lesson.dao.SysDeptDao;
import com.yingxue.lesson.entity.SysDept;
import com.yingxue.lesson.exception.BaseResponseCode;
import com.yingxue.lesson.exception.BusinessException;
import com.yingxue.lesson.service.SysDeptService;
import com.yingxue.lesson.utils.CodeUtil;
import com.yingxue.lesson.vo.req.DeptAddReqVO;
import com.yingxue.lesson.vo.resp.DeptRespNodeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;


@Slf4j
@Service("sysDeptService")
public class SysDeptServiceImpl implements SysDeptService {

    @Resource
    private SysDeptDao sysDeptDao;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public SysDept queryById(String id) {
        return this.sysDeptDao.queryById(id);
    }

    /**
     * 分页查询
     *
     * @param sysDept 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    public Page<SysDept> queryByPage(SysDept sysDept, PageRequest pageRequest) {
        long total = this.sysDeptDao.count(sysDept);
        return new PageImpl<>(this.sysDeptDao.queryAllByLimit(sysDept, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param sysDept 实例对象
     * @return 实例对象
     */
    @Override
    public SysDept insert(SysDept sysDept) {
        this.sysDeptDao.insert(sysDept);
        return sysDept;
    }

    /**
     * 修改数据
     *
     * @param sysDept 实例对象
     * @return 实例对象
     */
    @Override
    public SysDept update(SysDept sysDept) {
        this.sysDeptDao.update(sysDept);
        return this.queryById(sysDept.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return this.sysDeptDao.deleteById(id) > 0;
    }

    /**
     * 查询所有部门接口
     * @return   List<SysDept>
     */
    @Override
    public List<SysDept> selectAll() {
        List<SysDept> sysDeptList = sysDeptDao.queryAll();
        // 查询上级部门名称
        for (SysDept sysDept : sysDeptList) {
            SysDept dept = sysDeptDao.queryById(sysDept.getPid());
            if(dept!=null){
                sysDept.setPidName(dept.getName());
            }
        }
        return sysDeptList;
    }

    /**
     * 新增内置部门
     */
    @PostConstruct
    public void init(){
        List<SysDept> sysDeptList = sysDeptDao.queryAll();
        if(CollectionUtils.isEmpty(sysDeptList)){
            SysDept sysDept = new SysDept();
            sysDept.setPid("-1");
            sysDept.setId("0");
            sysDept.setName("默认顶级部门");
            // 部门编号
            Long deptCount = redisTemplate.opsForValue().increment(Constant.DEPT_CODE_KEY, 1);
            String deptCode = CodeUtil.deptCode(String.valueOf(deptCount),7,"0");
            sysDept.setDeptNo(deptCode);
            // 部门层级关系
            sysDept.setRelationCode(deptCode);
            sysDeptDao.insertSelective(sysDept);
        }
    }

    /**
     * 获取部门树
     * @return
     */
    @Override
    public List<DeptRespNodeVO> deptTreeList() {
        List<DeptRespNodeVO> result = new ArrayList<>();
        // 查询所有部门
        List<SysDept> sysDeptList = sysDeptDao.queryAll();
        // 查询顶级父级部门
        SysDept sysDept = sysDeptDao.queryById("0");
        DeptRespNodeVO deptRespNodeVO = new DeptRespNodeVO();
        BeanUtils.copyProperties(sysDept,deptRespNodeVO);
        deptRespNodeVO.setTitle(sysDept.getName());
        // 设置顶级父级部门的子节点
        deptRespNodeVO.setChildren(getChildren(sysDept.getId(),sysDeptList));
        result.add(deptRespNodeVO);
        return result;
    }

    /**
     * 新增部门
     * @param deptAddReqVO
     * @return
     */
    @Override
    public SysDept addDept(DeptAddReqVO deptAddReqVO) {
        // 部门基本信息
        SysDept sysDept = new SysDept();
        BeanUtils.copyProperties(deptAddReqVO,sysDept);
        sysDept.setId(UUID.randomUUID().toString());
        sysDept.setCreateTime(new Date());

        // 部门层级关系
        // deptCode是为了维护relationCode，即维护层级关系
        // incr命令将key中储存的数字值增1。如果key不存在，那么key的值会先被初始化为0,然后再执行incr操作。
        Long deptCount = redisTemplate.opsForValue().increment(Constant.DEPT_CODE_KEY, 1);
        String deptCode = CodeUtil.deptCode(String.valueOf(deptCount),7,"0");
        // relationCode=父级部门的deptCode+当前部门的deptCode
        // 获取父级部门的deptCode
        SysDept parent = sysDeptDao.queryById(sysDept.getPid());
        if(parent==null){
            log.info("父级部门不存在{}",sysDept.getPid());
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        String relationCode = parent.getRelationCode()+deptCode;
        sysDept.setDeptNo(deptCode);
        sysDept.setRelationCode(relationCode);

        sysDeptDao.insertSelective(sysDept);
        return sysDept;
    }

    /**
     * 递归获取子树
     * @param id
     * @param sysDeptList
     * @return
     */
    private List<DeptRespNodeVO> getChildren(String id, List<SysDept> sysDeptList) {
        List<DeptRespNodeVO> result = new ArrayList<>();
        for(SysDept sysDept:sysDeptList){
            if(sysDept.getPid().equals(id)){
                DeptRespNodeVO deptRespNodeVO = new DeptRespNodeVO();
                BeanUtils.copyProperties(sysDept,deptRespNodeVO);
                deptRespNodeVO.setTitle(sysDept.getName());
                deptRespNodeVO.setChildren(getChildren(sysDept.getId(),sysDeptList));
                result.add(deptRespNodeVO);
            }
        }
        return result;
    }
}
